﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using System.Threading;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Parameter;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;

namespace PSE.Deployment.SetupBase.Steps
{
    public class InstallWindowsService : SetupStep<Configuration.Actions.InstallWindowsService>
    {
        public InstallWindowsService(IStepGroup parent, Group group, Configuration.Actions.InstallWindowsService action, Parameter.Enums.SetupMode setupMode)
            : base(parent, group, action, setupMode)
        {
            this.ResetProgress(Action.Services.Count);
        }

        public override void Execute()
        {
            this.ResetProgress(Action.Services.Count);

            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                InstallServices();
            }
            else if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
            {
                UninstallArtefacts();
            }
        }

        public override void Undo()
        {
            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                UninstallArtefacts();
            }
        }

        private void InstallServices()
        {
            foreach (WindowsService service in Action.Services)
            {
                if (this.IsStopped())
                    return;

                string destination = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, service.ServiceFile.Destination);
                string fileName = destination + service.ServiceFile.FileName;

                this.IncrementProgress(service.DisplayName);

                string message = string.Empty;

                PSE.Deployment.Util.WindowsService.ServiceInfo serviceInfo = PSE.Deployment.Util.WindowsService.GetServiceInfo(service.ServiceName);

                if (serviceInfo == null)
                {
                    if (PSE.Deployment.Util.WindowsService.InstallService(service.ServiceName, fileName, out message))
                    {
                        this.AddUsedBy(fileName);
                    }
                    else
                    {
                        this.DecrementProgress(fileName);
                        throw new Exception(string.Format("Não foi possível instalar o serviço {0}" + Environment.NewLine + message, service.DisplayName));
                    }
                }

                if (service.Start)
                {
                    if (service.ServiceName == SetupMainFactory.GetInstance().HosterName)
                        PSE.Deployment.Util.WindowsServiceController.Start(service.ServiceName, new string[] { "false" });
                    else
                        PSE.Deployment.Util.WindowsServiceController.Start(service.ServiceName);
                }
            }
        }

        protected override void UninstallArtefact(string artefactName)
        {
            WindowsService service = Action.Services.Find(s => SetupMainFactory.GetInstance().Parameter.InstallationPath + s.ServiceFile.Destination + s.ServiceFile.FileName == artefactName);

            string message = string.Empty;

            if (!PSE.Deployment.Util.WindowsService.UninstallService(service.ServiceName, artefactName, out message))
                throw new Exception(string.Format("Não foi possível desinstalar o serviço {0}" + Environment.NewLine + message, service.DisplayName));

            WaitServiceFinalize(service.ServiceFile.FileName, new TimeSpan(0, 0, 1, 0, 0).Milliseconds);

            if (service.ServiceName == SetupMainFactory.GetInstance().HosterName)
                DeleteHosterFile();
        }

        private void DeleteHosterFile()
        {
            string hosterFile = string.Format(@"{0}\BMFBOVESPA\ServiceHoster\user.config", PSE.Deployment.Util.Windows.GetFolderPath(PSE.Deployment.Util.Windows.SpecialFolder.ApplicationData));

            if (File.Exists(hosterFile))
                File.Delete(hosterFile);

            if (Directory.Exists(Path.GetDirectoryName(hosterFile)))
                PSE.Deployment.Util.File.DeleteEmptyDirectories(SetupMainFactory.GetInstance().Parameter.InstallationPath, Path.GetDirectoryName(hosterFile));
        }

        private void WaitServiceFinalize(string serviceName, int timeOut)
        {
            int wait = 2000;
            int waitAcum = 0;
            //aguardar a finalizacao do processo 
            while (waitAcum < timeOut)
            {
                Process[] processList = Process.GetProcessesByName(serviceName);
                if (processList.Length == 0)
                {
                    break;
                }
                Thread.Sleep(wait);//aguardar 2 segundos antes de verificar novamente se o hoster foi removido
                waitAcum += wait;
            }
        }
    }
}
